﻿using System;
using System.Diagnostics;
using System.Text;

namespace Anno.Util
{
    public class Linux
	{
		/// <summary>
		/// 
		/// </summary>
		public string Output { get; private set; }

		/// <summary>
		/// 
		/// </summary>
		public string[] Lines
		{
			get
			{
				string output = this.Output;
				if (output == null)
				{
					return null;
				}
				return output.Split(Environment.NewLine.ToCharArray());
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public int ExitCode { get; private set; }

		/// <summary>
		/// 
		/// </summary>
		public string ErrorMsg { get; private set; }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="input"></param>
		/// <param name="workingDirectory"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		/// <exception cref="PlatformNotSupportedException"></exception>
		public BashResult Command(string input, string workingDirectory, bool redirect)
		{
			if (!Anno.Util.Bash.Native)
			{
				throw new PlatformNotSupportedException();
			}
			int id = 0;
			using (Process process = new Process
			{
				StartInfo = this.BashInfo(input, workingDirectory, redirect)
			})
			{
				process.Start();
				id = process.Id;
				if (!redirect)
				{
					this.Output = null;
					this.ErrorMsg = null;
				}
				if (process.WaitForExit(1000))
				{
					this.ExitCode = process.ExitCode;
				}
				process.Close();
			}
			if (redirect)
			{
				return new BashResult(this.Output, this.ErrorMsg, this.ExitCode, id);
			}
			return new BashResult(null, null, this.ExitCode, id);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="pid"></param>
		public void KillProcessAndChildren(int pid)
		{
			if (pid < 0)
			{
				return;
			}
			try
			{
				Process.GetProcessById(pid).Kill();
			}
			catch (Exception)
			{
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="input"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Command(string input, bool redirect)
		{
			return this.Command(input, null, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public BashResult Command(string input)
		{
			return this.Command(input, true);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="input"></param>
		/// <param name="workingDirectory"></param>
		/// <param name="redirectOutput"></param>
		/// <returns></returns>
		private ProcessStartInfo BashInfo(string input, string workingDirectory, bool redirectOutput)
		{
			ProcessStartInfo processStartInfo = new ProcessStartInfo
			{
				FileName = Anno.Util.Bash._bashPath,
				Arguments = "-c \"" + input + "\"",
				RedirectStandardInput = false,
				RedirectStandardOutput = redirectOutput,
				RedirectStandardError = redirectOutput,
				UseShellExecute = false,
				CreateNoWindow = true,
				StandardOutputEncoding = Encoding.UTF8,
				ErrorDialog = false
			};
			if (!string.IsNullOrWhiteSpace(workingDirectory))
			{
				processStartInfo.WorkingDirectory = workingDirectory;
			}
			return processStartInfo;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="input"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Echo(string input, bool redirect = false)
		{
			return this.Command("echo " + input, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="input"></param>
		/// <param name="flags"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Echo(string input, string flags, bool redirect = false)
		{
			return this.Command("echo " + flags + " " + input, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="input"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Echo(object input, bool redirect = false)
		{
			return this.Command(string.Format("echo {0}", input), redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="input"></param>
		/// <param name="flags"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Echo(object input, string flags, bool redirect = false)
		{
			return this.Command(string.Format("echo {0} {1}", flags, input), redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="pattern"></param>
		/// <param name="location"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Grep(string pattern, string location, bool redirect = true)
		{
			return this.Command("grep " + pattern + " " + location, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="pattern"></param>
		/// <param name="location"></param>
		/// <param name="flags"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Grep(string pattern, string location, string flags, bool redirect = true)
		{
			return this.Command(string.Concat(new string[]
			{
				"grep ",
				pattern,
				" ",
				flags,
				" ",
				location
			}), redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Ls(bool redirect = true)
		{
			return this.Command("ls", redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="flags"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Ls(string flags, bool redirect = true)
		{
			return this.Command("ls " + flags, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="flags"></param>
		/// <param name="files"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Ls(string flags, string files, bool redirect = true)
		{
			return this.Command("ls " + flags + " " + files, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="source"></param>
		/// <param name="directory"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Mv(string source, string directory, bool redirect = true)
		{
			return this.Command("mv " + source + " " + directory, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="source"></param>
		/// <param name="directory"></param>
		/// <param name="flags"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Mv(string source, string directory, string flags, bool redirect = true)
		{
			return this.Command(string.Concat(new string[]
			{
				"mv ",
				flags,
				" ",
				source,
				" ",
				directory
			}), redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="source"></param>
		/// <param name="directory"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Cp(string source, string directory, bool redirect = true)
		{
			return this.Command("cp " + source + " " + directory, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="source"></param>
		/// <param name="directory"></param>
		/// <param name="flags"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Cp(string source, string directory, string flags, bool redirect = true)
		{
			return this.Command(string.Concat(new string[]
			{
				"cp ",
				flags,
				" ",
				source,
				" ",
				directory
			}), redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="file"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Rm(string file, bool redirect = true)
		{
			return this.Command("rm " + file, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="file"></param>
		/// <param name="flags"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Rm(string file, string flags, bool redirect = true)
		{
			return this.Command("rm " + flags + " " + file, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="file"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Cat(string file, bool redirect = true)
		{
			return this.Command("cat " + file, redirect);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="file"></param>
		/// <param name="flags"></param>
		/// <param name="redirect"></param>
		/// <returns></returns>
		public BashResult Cat(string file, string flags, bool redirect = true)
		{
			return this.Command("cat " + flags + " " + file, redirect);
		}

		/// <summary>
		/// Bash命令
		/// </summary>
		/// <param name="command"></param>
		/// <returns></returns>
		public static string Bash(string command)
		{
			var escapedArgs = command.Replace("\"", "\\\"");
			var process = new Process()
			{
				StartInfo = new ProcessStartInfo
				{
					FileName = "/bin/bash",
					Arguments = $"-c \"{escapedArgs}\"",
					RedirectStandardOutput = true,
					UseShellExecute = false,
					CreateNoWindow = true,
				}
			};
			process.Start();
			string result = process.StandardOutput.ReadToEnd();
			process.WaitForExit();
			process.Dispose();
			return result;
		}
	}
}
